/**
 * @fileOverview
 * @name circle-user.js
 * @author lidh04
 * @license copyright to shc
 */

import Cookies from 'js-cookie';
import { writeFile, mkdir } from 'node:fs/promises';
import path from 'path';
import { buildUrl, getData, postData, COOKIE_KEY, isBrowser } from "./circle-common.js";
import gateway from "./circle-gateway.js";

/// <reference path="./circle-types.js" />

/**
 * the common account object
 * @typedef {Object} AccountPO
 * @property {string} [email] - the account email
 * @property {string} [phone] - the account phone
 * @property {number} [userType] - the user type
 */

/**
 * send register verify code to user
 * @param {Object} input - user input
 * @param {string} [input.email] - user's email
 * @param {string} [input.phone] - user's phone
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @return { Promise<BooleanResponse> } - the result.
 */
export async function sendRegisterVerifyCode(input) {
  const url = buildUrl(gateway.user.path.sendRegisterVerifyCode);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * register api.
 * @param {Object} input - user input
 * @param {string} [input.email]
 * @param {string} [input.phone]
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @param {string} input.passwordInput1
 * @param {string} input.passwordInput2
 * @param {string} input.verifyCode
 * @returns {Promise<BooleanResponse>}  - the result.
 */
export async function register(input) {
  const url = buildUrl(gateway.user.path.register);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * send login verify code
 * @param {Object} input - user input.
 * @param {string} [input.email] - the user email
 * @param {string} [input.phone] - the user phone
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @returns {Promise<BooleanResponse>} - the result.
 */
export async function sendVerifyCode(input) {
  const url = buildUrl(gateway.user.path.sendVerifyCode);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * @typedef {Object} UserLoginResult
 * @property {string} userId - the user id
 * @property {string} sessionKey - the session key
 * @property {number} sex - the sex
 * @property {boolean} success - the success flag.
 */

/**
 * @typedef {Object} LoginResponse
 * @property {number} status  - the response status
 * @property {string} message - the response message
 * @property {UserLoginResult} data - the login result
 */

/**
 * login api
 * @param {Object} input - user input
 * @param {string} [input.email] - user's email,
 * @param {string} [input.phone] - user's phone,
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @param {string} [input.verifyCode] - the login verify code
 * @param {string} [input.password] - the login password
 
 * @returns {Promise<LoginResponse>} - the result
 */
export async function login(input) {
  const url = buildUrl(gateway.user.path.login);
  /**
   *@type {LoginResponse}
   */
  const response = await postData(url, input, +gateway.http.timeoutWrite);
  const { status, data } = response;
  if (status === 200) {
    const { userId, sessionKey } = data;
    const { email, phone } = input;
    const userType = email ? 1 : 0;
    const userLoginInfo = {
      userId,
      userType,
      sessionKey,
      email,
      phone,
    };
    await saveUserLoginInfo(userLoginInfo);
  }

  return response;
}

/**
 * save user login info in sessionPath
 * @param {Object} userLoginInfo - the user login info.
 * @param {string} userLoginInfo.userId - the user id
 * @param {number} userLoginInfo.userType - the user type 0: email, 1: phone
 * @param {string} userLoginInfo.sessionKey - the session key
 * @param {string} [userLoginInfo.email] - the user email
 * @param {string} [userLoginInfo.phone] - the user phone
 * @returns {Promise<void>} - no returns.
 */
export async function saveUserLoginInfo(userLoginInfo) {
  if (isBrowser()) {
    Cookies.set(COOKIE_KEY, JSON.stringify(userLoginInfo), {
      expires: 7, path: '/'
    });
    return;
  }

  const { userId, userType, sessionKey, email, phone } = userLoginInfo;
  const sessionPath = gateway.user.sessionPath;
  const home = process.env.HOME;
  const sessionFullPath = `${home}/${sessionPath}`;
  const accountInfo = email ? `email=${email}` : `phone=${phone}`;
  const content = `##### user login information
# ${new Date().toISOString()}
userId=${userId}
userType=${userType}
sessionKey=${sessionKey}
${accountInfo}
`;
  try {
    const dir = path.dirname(sessionFullPath);
    await mkdir(dir, { recursive: true });
    await writeFile(sessionFullPath, content);
  } catch (err) {
    console.error("cannot save user login info:", JSON.stringify(userLoginInfo), "to session path:", sessionFullPath);
  }
}

/**
 * logout api
 * @returns {Promise<BooleanResponse>} - the result.
 */
export async function logout() {
  const url = buildUrl(gateway.user.path.logout);
  return postData(url, {}, +gateway.http.timeoutWrite);
}

/**
 * send reset password verify code
 * @param {Object} input - the user input
 * @param {string} [input.email] - the user email
 * @param {string} [input.phone] - the user phone
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @returns {Promise<BooleanResponse>} - the result.
 */
export async function sendResetPasswordVerifyCode(input) {
  const url = buildUrl(gateway.user.path.sendResetPasswordVerifyCode);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * reset login password.
 * @param {Object} input - the user input
 * @param {AccountPO} input.account - the account
 * @param {string} input.verifyCode - the verify code
 * @param {string} input.password1  - the new password
 * @param {string} input.password2  - the password confirmed.
 * @returns {Promise<BooleanResponse>} - the reset login password result.
 */
export async function resetPassword(input) {
  const url = buildUrl(gateway.user.path.resetPassword);
  return postData(url, input, +gateway.http.timeoutWrite);
}


/**
 * send set pay password verify code
 * @param {Object} input - the user input
 * @param {string} [input.email] - the user email
 * @param {string} [input.phone] - the user phone
 * <br/>input conditions:<br/>
 * 1. The email and phone should not be empty both.<br/>
 * 2. If the email is not empty, the phone should be empty.<br/>
 * 3. If the phone is not empty, the email should be empty.<br/>
 * @returns {Promise<BooleanResponse>} - the send result.
 */
export async function sendPayVerifyCode(input) {
  const url = buildUrl(gateway.user.path.sendPayVerifyCode);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * set the pay password
 * @param {Object} input - the user input
 * @param {AccountPO} input.account - the account
 * @param {string} input.verifyCode - the verify code
 * @param {string} input.password   - the new pay password.
 * @returns {Promise<BooleanResponse>} - the set pay password result.
 */
export async function setPayPassword(input) {
  const url = buildUrl(gateway.user.path.setPayPassword);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * check the account weather have the pay password.
 * @returns {Promise<BooleanResponse>} - the result.
 */
export async function havePayPassword() {
  const url = buildUrl(gateway.user.path.havePayPassword);
  return getData(url, +gateway.http.timeoutRead);
}

/**
 * save or update user info.
 * @param {Object} input - the user input
 * @param {string} input.userId - the userId
 * @param {string} [input.name] - the user name
 * @param {string} [input.phone] - the user phone
 * @param {number} [input.sex] - the use sex 1: male, 0: woman
 * @param {string} [input.icon] - the user icon
 * @param {string} [input.address] - the user address
 * @param {number} [input.motherLang] - the mother language
 * @param {string} [input.wechat] - the wechat
 * @param {string} [input.entWechat] - the enterprise wechat
 * @param {string} [input.dingtalk] - the dingtalk
 * @returns {Promise<BooleanResponse>} - the save or update response.
 */
export async function saveOrUpdateUserInfo(input) {
  const url = buildUrl(gateway.user.path.saveOrUpdateUserInfo);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * add contacts.
 * @param {Object} input - the user input.
 * @param {string} [input.phone] - the user phone
 * @param {string} [input.name] - the user name
 * @param {number} [input.sex] - the user sex 1: male, 0 woman.
 * @param {string} [input.icon] - the user icon
 * @param {string} [input.address] - the user address
 * @param {string} [input.description] - the description.
  * @returns {Promise<BooleanResponse>} - the add contacts response.
 */
export async function addContacts(input) {
  const url = buildUrl(gateway.user.path.addContacts);
  return postData(url, input, +gateway.http.timeoutWrite);
}

/**
 * @typedef {Object} UserInfoPO
 * @property {string} userId - the user id
 * @property {string} [name] - the user name
 * @property {string} [phone] - the user phone
 * @property {number} [sex] - the user sex 1: male, 0: woman
 * @property {string} [icon] - the user icon
 * @property {string} [address] - the user's address
 * @property {number} [motherLang] - the mother language
 * @property {string} [wechat] - the wechat
 * @property {string} [entWechat] - the enterprise wechat.
 * @property {string} [dingtalk] - the dingtalk.
 */

/**
 * @typedef {Object} UserInfoResponse
 * @property {number} status - the response status
 * @property {string} message - the response message
 * @property {UserInfoPO} data - the data.
 */

/**
 * get the user info of the account.
 * @returns {Promise<UserInfoResponse>} - the user info response.
 */
export async function userInfo() {
  const url = buildUrl(gateway.user.path.userInfo);
  return getData(url, +gateway.http.timeoutRead);
}

/**
 * @typedef {Object} ContactPO
 * @property {string} [phone] - user phone
 * @property {string} [name] - user name
 * @property {number} [sex] - user sex 1: male, 0 woman
 * @property {string} [icon] - user icon
 * @property {string} [address] - user address
 * @property {string} [description] - the description
 */

/**
 * @typedef {Object} ContactsResponse
 * @property {number} status - the response status
 * @property {string} message - the response message
 * @property {ContactPO[]} data - the data.
 *
 */

/**
 * list all the contacts.
 * @returns {Promise<ContactsResponse>} - the list contacts response.
 */
export async function listContacts() {
  const url = buildUrl(gateway.user.path.listContacts);
  return getData(url, +gateway.http.timeoutRead);
}
